package com.nanchen.compresshelper;


import ohos.agp.render.Canvas;
import ohos.agp.render.Paint;
import ohos.agp.render.PixelMapHolder;
import ohos.agp.render.Texture;
import ohos.agp.utils.Matrix;
import ohos.agp.utils.TextTool;
import ohos.app.Context;
import ohos.media.image.ImagePacker;
import ohos.media.image.common.PixelFormat;
import ohos.media.image.common.Size;
import ohos.utils.net.Uri;
import ohos.media.image.PixelMap;
import ohos.media.image.ImageSource;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

/**
 * 图片处理工具类
 * <p>
 * Author: nanchen
 * Email: liushilin520@foxmail.com
 * Date: 2017-03-08  9:03
 */

public class BitmapUtil {

    private BitmapUtil() {
        throw new UnsupportedOperationException("u can't instantiate me...");
    }

    static PixelMap getScaledBitmap(Context context, Uri imageUri, float maxWidth, float maxHeight, PixelFormat bitmapConfig) {
        String filePath = FileUtil.getRealPathFromURI(context, imageUri);
        PixelMap scaledBitmap = null;

        ImageSource.DecodingOptions options = new ImageSource.DecodingOptions();
        ImageSource imageSource = ImageSource.create(filePath, null);
        Size size = imageSource.getImageInfo().size;
        options.desiredSize = size;
        int actualHeight = size.height;
        int actualWidth = size.width;
        PixelMap bmp;

        float imgRatio = (float) actualWidth / actualHeight;
        float maxRatio = maxWidth / maxHeight;

        //width and height values are set maintaining the aspect ratio of the image
        if (actualHeight > maxHeight || actualWidth > maxWidth) {
            if (imgRatio < maxRatio) {
                imgRatio = maxHeight / actualHeight;
                actualWidth = (int) (imgRatio * actualWidth);
                actualHeight = (int) maxHeight;
            } else if (imgRatio > maxRatio) {
                imgRatio = maxWidth / actualWidth;
                actualHeight = (int) (imgRatio * actualHeight);
                actualWidth = (int) maxWidth;
            } else {
                actualHeight = (int) maxHeight;
                actualWidth = (int) maxWidth;
            }
        }

        //setting inSampleSize value allows to load a scaled down version of the original image
        options.sampleSize = calculateInSampleSize(options, actualWidth, actualHeight);

        bmp = imageSource.createPixelmap(options);

        if (actualHeight <= 0 || actualWidth <= 0) {
            return null;
        }

        try {
            PixelMap.InitializationOptions scaledOptions = new PixelMap.InitializationOptions();
            scaledOptions.size = new Size(actualWidth, actualHeight);
            scaledOptions.pixelFormat = bitmapConfig;
            scaledBitmap = PixelMap.create(scaledOptions);
        } catch (OutOfMemoryError exception) {
            exception.printStackTrace();
        }

        float ratioX = actualWidth / (float) options.desiredSize.width;
        float ratioY = actualHeight / (float) options.desiredSize.height;

        Matrix scaleMatrix = new Matrix();
        scaleMatrix.setScale(ratioX, ratioY, 0, 0);

        Canvas canvas = new Canvas();
        canvas.setTexture(new Texture(scaledBitmap));
        canvas.setMatrix(scaleMatrix);
        canvas.drawPixelMapHolder(new PixelMapHolder(bmp), 0, 0, new Paint());

        return scaledBitmap;
    }

    static File compressImage(Context context, Uri imageUri, float maxWidth, float maxHeight,
                              String compressFormat, PixelFormat bitmapConfig,
                              int quality, String parentPath, String prefix, String fileName) {
        FileOutputStream out = null;
        String filename = null;
        try {
            filename = generateFilePath(context, parentPath, imageUri, compressFormat.toLowerCase(), prefix, fileName);
        } catch (IOException e) {
            e.printStackTrace();
        }
        try {
            out = new FileOutputStream(filename);
            // 通过文件名写入
            PixelMap newBmp = BitmapUtil.getScaledBitmap(context, imageUri, maxWidth, maxHeight, bitmapConfig);

            if (newBmp != null) {
                ImagePacker imagePacker = ImagePacker.create();
                ImagePacker.PackingOptions options = new ImagePacker.PackingOptions();
                options.format = compressFormat;//image/jpeg
                options.quality = quality;
                imagePacker.initializePacking(out, options);
                imagePacker.addImage(newBmp);
                long l = imagePacker.finalizePacking();
            }

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } finally {
            try {
                if (out != null) {
                    out.close();
                }
            } catch (IOException ignored) {
            }
        }

        return new File(filename);
    }

    private static String generateFilePath(Context context, String parentPath, Uri uri,
                                           String extension, String prefix, String fileName) throws IOException {
        File file = new File(parentPath);
        if (!file.exists()) {
            file.mkdirs();
        }
        /** if prefix is null, set prefix "" */
        prefix = TextTool.isNullOrEmpty(prefix) ? "" : prefix;
        /** reset fileName by prefix and custom file name */
        fileName = TextTool.isNullOrEmpty(fileName) ? prefix + FileUtil.splitFileName(FileUtil.getFileName(context, uri))[0] : fileName;
        return file.getCanonicalPath() + File.separator + fileName + "." + "jpg";
    }


    /**
     * 计算inSampleSize
     */
    private static int calculateInSampleSize(ImageSource.DecodingOptions options, int reqWidth, int reqHeight) {

        final int height = options.desiredSize.height;
        final int width = options.desiredSize.width;
        int inSampleSize = 1;

        if (height > reqHeight || width > reqWidth) {
            final int heightRatio = Math.round((float) height / (float) reqHeight);
            final int widthRatio = Math.round((float) width / (float) reqWidth);
            inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
        }

        final float totalPixels = width * height;
        final float totalReqPixelsCap = reqWidth * reqHeight * 2;

        while (totalPixels / (inSampleSize * inSampleSize) > totalReqPixelsCap) {
            inSampleSize++;
        }

        return inSampleSize;
    }
}
